package cn.doitedu.kafka.day02

import java.time.Duration
import java.util
import java.util.Properties

import org.apache.kafka.clients.consumer.{KafkaConsumer, OffsetAndMetadata, OffsetCommitCallback}
import org.apache.kafka.common.TopicPartition
import org.apache.kafka.common.serialization.StringDeserializer

/**
 * 关闭消费者自动提交偏移量，而是每消费一批数据后，再调用提交偏移量的方法，
 * 将偏移量写入的kafka特殊的topic中
 *
 *
 */
object ConsumerDemo3 {

  def main(args: Array[String]): Unit = {

    val properties = new Properties()
    //指定broker地址
    properties.setProperty("bootstrap.servers", "node-1.51doit.cn:9092,node-2.51doit.cn:9092,node-3.51doit.cn:9092")
    //指定key反序列化方式
    properties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
    //指定value反序列化方式
    properties.setProperty("value.deserializer", classOf[StringDeserializer].getName) // 两种写法都行
    //指定消费者组ID
    properties.setProperty("group.id", "g1113")
    //从头开始消费
    //earliest：从头开始 --from-beginning
    //latest:从消费者启动之后
    //如果指定了"auto.offset.reset","earliest"，消费者启动是会读取对应消费者组ID的偏移量
    //如果没有历史偏移量，就从头读，有偏移量，就继续读
    properties.setProperty("auto.offset.reset", "earliest") //[latest, earliest, none]
    //是不是开启自动提交偏移量，默认为true
    //还是手动更新偏移量好呢？ (更精准)
    properties.setProperty("enable.auto.commit", "false")

    //创建KafkaConsumer，并关联properties
    val consumer = new KafkaConsumer[String, String](properties)

    val topics: util.List[String] = util.Arrays.asList("test")
    //订阅指定的一个或多个topic
    consumer.subscribe(topics)

    //不停地循环
    while (true) {
      //拉取数据，返回的是consumerRecords，是Iterable
      //如果拉取到一个批次数据，立即返回，如果没有拉取到新的数据，最多等待值的时间
      //println(666)
      val consumerRecords = consumer.poll(Duration.ofSeconds(10))
      //如果该批次取出数据，就处理数据，然后提交偏移量
      if (!consumerRecords.isEmpty) {
        //使用scala的for循环遍历
        import scala.collection.JavaConverters._
        for (record <- consumerRecords.asScala) {
          println(record)
        }
        //处理完当前读处理的批次的数据，提交一次偏移量
        //consumer.commitSync() //同步提交，该方法是阻塞的，没有提交成功，代码不会继续执行
        consumer.commitAsync() //异步提交偏移量，即开启一个新的线程提交偏移量，方法不会阻塞，读取数据的效率更高
        //异步已经并且提交偏移量成功或失败有对应的回调方法
//        consumer.commitAsync(new OffsetCommitCallback() {
//          //提交完成了，但是可能失败，也可能成功
//          override def onComplete(offsets: util.Map[TopicPartition, OffsetAndMetadata], exception: Exception): Unit = {
//            //offsets返回最新的偏移量
//            //exception如果不为空，说明提交偏移量出现了异常
//            //再提交偏移量
//            consumer.commitSync(offsets) //同步已经，提交指定的偏移量
//          }
//        })
      }
    }


  }
}
